package com.abel.bigwater.wflow

import com.abel.bigmeter.service.MeterParam
import com.abel.bigwater.wflow.mapper.MeterMapper
import org.activiti.api.process.model.builders.StartProcessPayloadBuilder
import org.activiti.api.process.runtime.ProcessRuntime
import org.activiti.api.task.runtime.TaskRuntime
import org.activiti.engine.ProcessEngine
import org.activiti.engine.impl.identity.Authentication
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.ui.set
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import java.util.*

@Controller
@RequestMapping("/alterMeter")
class AlterMeterController {

    @Autowired
    var processRuntime: ProcessRuntime? = null

    @Autowired
    var taskRuntime: TaskRuntime? = null

    @Autowired
    var processEngine: ProcessEngine? = null

    @Autowired
    var meterMapper: MeterMapper? = null

    /**
     * claim instance for this process.
     */
    @RequestMapping("/claimInst/{pid}")
    fun claimInst(m: Model, @PathVariable("pid") pid: String): String {
        val me = DemoApplicationConfiguration.myself()

        val pd = processRuntime!!.processDefinition(pid)
        m.set("pd", pd)

        val meterList = meterMapper!!.selectMeter(MeterParam(firmId = me!!.firmId))
        m.set("meterList", meterList)

        return "start_alter_meter"
    }

    /**
     * claim instance for this process.
     */
    @RequestMapping("/startInst/{pid}")
    fun startInst(m: Model, @PathVariable("pid") pid: String,
                  @RequestParam("meterId") _meterId: String,
                  @RequestParam("faultType") _faultType: String): String {
        val me = DemoApplicationConfiguration.myself()
        me ?: return URL_LOGIN

        val user = SecurityContextHolder.getContext().authentication.principal as UserDetails

        val pd = processRuntime!!.processDefinition(pid)
        m.set("pd", pd)

        val meter = meterMapper!!.selectMeter(MeterParam(firmId = me.firmId, meterId = _meterId)).firstOrNull()
        if (meter == null) {
            m.set("errors", arrayOf("水表没找到: ${_meterId}"))
            return "error-list"
        }

        m.set("meter", meter)

        Authentication.setAuthenticatedUserId(user.username)

        val pinst = processRuntime!!.start(StartProcessPayloadBuilder()
                .withProcessDefinitionId(pid)
                .withBusinessKey("AlterMeter@${_meterId}@${me.firmId}@01")
                .withName(meter.name)
                .withVariable("meterId", _meterId)
                .withVariable("firmId", meter.firmId)
                .withVariable("meterCode", meter.meterCode)
                .withVariable("userCode", meter.userCode)
                .withVariable("meterName", meter.name)
                .withVariable("faultType", _faultType)
                .withVariable("faultTime", Date())
                .withVariable("applyUserId", user.username)
                .build())
        m.set("pinst", pinst)

        return "/lossMng/pinstList"
    }

    /**
     * 签收任务
     */
    @RequestMapping("/claimTask/{taskId}")
    fun claimTask(m: Model, @PathVariable("taskId") taskId: String): String {
        val me = DemoApplicationConfiguration.myself()
        me ?: return URL_LOGIN

        val errors = arrayListOf<String>()
        m.set("errors", errors)

        val task = taskRuntime?.task(taskId)
        if (task == null) {
            errors.add("未找到任务: ${taskId}")

            return ERROR_LIST
        }

        val pinst = processRuntime?.processInstance(task.processInstanceId)

        errors.add("暂不支持签收该任务: ${task.name}(${taskId})")
        return ERROR_LIST
    }

    /**
     * 显示进度图
     */
    @RequestMapping("/currentDiagram/{pinstId}")
    fun currentDiagram(m: Model, @PathVariable("pinstId") pinstId: String): String {
        val me = DemoApplicationConfiguration.myself()
        me ?: return URL_LOGIN

        val pd = processRuntime?.processInstance(pinstId)
        val aids = processRuntime?.processInstanceMeta(pinstId)?.activeActivitiesIds
        lgr.info("active activity id list: ${aids?.joinToString()}")

        val bmodel = processEngine?.repositoryService?.getBpmnModel(pd?.processDefinitionId)

        val giList = bmodel?.locationMap?.filterKeys { gk ->
            aids?.contains(gk) == true
        }?.values
        m.set("giList", giList!!)

        return "alter-meter-diagram"
    }

    companion object {
        private val lgr = LoggerFactory.getLogger(AlterMeterController::class.java)

        const val URL_LOGIN = "redirect:/login"

        const val ERROR_LIST = "error-list"
    }
}